﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Numerics;
using System.Text;
using ParserGenerator.Exceptions;
using ParserGenerator.Extensions;
using ParserGenerator.Output;

namespace ParserGenerator.SyntacticAnalysis
{
    partial class SyntaxTreeNodeWriter
    {
        protected const int PrimaryExpressionOpPrecedence = 21;
        protected const int PostfixExpressionOpPrecedence = 20;
        protected const int TypeCheckExpressionOpPrecedence = 19;
        protected const int AwaitExpressionOpPrecedence = 18;
        protected const int PowerExpressionOpPrecedence = 17;
        protected const int UnaryExpressionOpPrecedence = 16;
        protected const int MultiplicativeExpressionOpPrecedence = 15;
        protected const int AdditiveExpressionOpPrecedence = 14;
        protected const int ShiftExpressionOpPrecedence = 13;
        protected const int BitwiseAndExpressionOpPrecedence = 12;
        protected const int BitwiseXorExpressionOpPrecedence = 11;
        protected const int BitwiseOrExpressionOpPrecedence = 10;
        protected const int RelationalOpValuePairOpPrecedence = 9;
        protected const int RelationalExpressionOpPrecedence = 8;
        protected const int LogicalNotExpressionOpPrecedence = 7;
        protected const int LogicalAndExpressionOpPrecedence = 6;
        protected const int LogicalOrExpressionOpPrecedence = 5;
        protected const int TestExpressionOpPrecedence = 4;
        protected const int YieldExpressionOpPrecedence = 3;
        protected const int FieldLabelValuePairOpPrecedence = 2;
        protected const int TargetExpressionOpPrecedence = 1;
        protected const int UnpackExpressionOpPrecedence = 0;

        protected const int PrimaryTypeExpressionOpPrecedence = 4;
        protected const int PostfixTypeExpressionOpPrecedence = 3;
        protected const int UnionTypeExpressionOpPrecedence = 2;
        protected const int FunctionTypeExpressionOpPrecedence = 1;
        protected const int TypeExpressionOpPrecedence = 0;

        protected const int PrimarySyntacticExpressionOpPrecedence = 3;
        protected const int PostfixSyntacticExpressionOpPrecedence = 2;
        protected const int ConcatSyntacticExpressionOpPrecedence = 1;
        protected const int SyntacticExpressionOpPrecedence = 0;

        protected const int PrimaryLexicalExpressionOpPrecedence = 3;
        protected const int PostfixLexicalExpressionOpPrecedence = 2;
        protected const int ConcatLexicalExpressionOpPrecedence = 1;
        protected const int LexicalExpressionOpPrecedence = 0;

        private static bool IsKeyword(string name)
        {
            if (name == null)
                throw new ArgumentNullException(nameof(name));
            switch (name)
            {
                case "False":
                case "None":
                case "True":
                case "abstract":
                case "add":
                case "alias":
                case "and":
                case "as":
                case "ascending":
                case "assert":
                case "async":
                case "attributes":
                case "await":
                case "base":
                case "bool":
                case "break":
                case "by":
                case "byte":
                case "case":
                case "catch":
                case "char":
                case "char16":
                case "char32":
                case "char8":
                case "checked":
                case "class":
                case "const":
                case "continue":
                case "decimal":
                case "def":
                case "default":
                case "define":
                case "del":
                case "delegate":
                case "descending":
                case "do":
                case "double":
                case "dynamic":
                case "elif":
                case "else":
                case "endmarker":
                case "enum":
                case "equals":
                case "event":
                case "except":
                case "exception":
                case "explicit":
                case "extern":
                case "false":
                case "finally":
                case "fixed":
                case "float":
                case "float32":
                case "float64":
                case "for":
                case "foreach":
                case "from":
                case "get":
                case "global":
                case "goal":
                case "goto":
                case "grammar":
                case "group":
                case "hidden":
                case "if":
                case "implicit":
                case "import":
                case "in":
                case "include":
                case "inf":
                case "infj":
                case "int":
                case "int16":
                case "int32":
                case "int64":
                case "int8":
                case "interface":
                case "internal":
                case "into":
                case "intptr_t":
                case "is":
                case "join":
                case "keyword":
                case "lambda":
                case "layout":
                case "left":
                case "let":
                case "lexprec":
                case "lock":
                case "long":
                case "nameof":
                case "namespace":
                case "nan":
                case "nanj":
                case "new":
                case "nonassoc":
                case "nonlocal":
                case "not":
                case "null":
                case "object":
                case "of":
                case "on":
                case "one":
                case "operator":
                case "or":
                case "orderby":
                case "out":
                case "override":
                case "params":
                case "partial":
                case "pass":
                case "prec":
                case "private":
                case "protected":
                case "ptrdiff_t":
                case "public":
                case "raise":
                case "readonly":
                case "reduce":
                case "ref":
                case "remove":
                case "reserved":
                case "return":
                case "reversed":
                case "right":
                case "sbyte":
                case "sealed":
                case "select":
                case "set":
                case "shift":
                case "short":
                case "size_t":
                case "sizeof":
                case "ssize_t":
                case "stackalloc":
                case "start":
                case "static":
                case "string":
                case "struct":
                case "switch":
                case "this":
                case "throw":
                case "token":
                case "true":
                case "try":
                case "type":
                case "typeof":
                case "uint":
                case "uint16":
                case "uint32":
                case "uint64":
                case "uint8":
                case "uintptr_t":
                case "ulong":
                case "unchecked":
                case "unit":
                case "unsafe":
                case "ushort":
                case "using":
                case "value":
                case "var":
                case "virtual":
                case "void":
                case "volatile":
                case "when":
                case "where":
                case "while":
                case "with":
                case "xstart":
                case "yield":
                    return true;
            }
            return false;
        }

        public virtual void WriteIdentifier(string n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (IsKeyword(n))
                writer.Write("`{0}`", n);
            else
                writer.Write(n);
        }

        public virtual void WriteIdentifier(Identifier n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WritePositionalArgument(PositionalArgument n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Value, writer);
        }

        public virtual void WritePositionalUnpackArgument(PositionalUnpackArgument n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("*");
            WriteExpression(n.Value, writer, BitwiseOrExpressionOpPrecedence);
        }

        public virtual void WriteKeywordArgument(KeywordArgument n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            writer.Write("=");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteKeywordUnpackArgument(KeywordUnpackArgument n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("**");
            WriteExpression(n.Value, writer, BitwiseOrExpressionOpPrecedence);
        }

        public virtual void WriteArgumentList(ArgumentList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteArgument(n.Items[i], writer);
            }
            writer.Write(")");
        }

        public virtual void WriteParameter(Parameter n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.Type != null)
            {
                writer.Write(": ");
                WriteTypeExpression(n.Type, writer);
            }
            if (n.Value != null)
            {
                writer.Write("=");
                WriteExpression(n.Value, writer);
            }
        }

        public virtual void WriteParameterList(ParameterList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            int output = 0;
            if (n.PositionalOnly.Count > 0)
            {
                foreach (Parameter item in n.PositionalOnly)
                {
                    if (output > 0)
                        writer.Write(", ");
                    WriteParameter(item, writer);
                    output++;
                }
                writer.Write(", /");
            }
            foreach (Parameter item in n.Positional)
            {
                if (output > 0)
                    writer.Write(", ");
                WriteParameter(item, writer);
                output++;
            }
            if (n.ExtraPositional != null)
            {
                if (output > 0)
                    writer.Write(", ");
                writer.Write("*");
                WriteParameter(n.ExtraPositional, writer);
                output++;
            }
            if (n.KeywordOnly.Count > 0)
            {
                if (n.ExtraPositional == null)
                {
                    if (output > 0)
                        writer.Write(", ");
                    writer.Write("*");
                    output++;
                }
                foreach (Parameter item in n.KeywordOnly)
                {
                    if (output > 0)
                        writer.Write(", ");
                    WriteParameter(item, writer);
                    output++;
                }
            }
            // TODO: **kwargs is missing
        }

        public virtual void WriteMapKeyValuePair(MapKeyValuePair n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Key, writer);
            writer.Write(": ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteFieldLabelValuePair(FieldLabelValuePair n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Label, writer);
            writer.Write("=");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteRelationalOp(RelationalOp n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n)
            {
                case RelationalOp.EqualTo: writer.Write("=="); break;
                case RelationalOp.NotEqualTo: writer.Write("!="); break;
                case RelationalOp.LessThan: writer.Write("<"); break;
                case RelationalOp.LessEqual: writer.Write("<="); break;
                case RelationalOp.GreaterThan: writer.Write(">"); break;
                case RelationalOp.GreaterEqual: writer.Write(">="); break;
                case RelationalOp.Is: writer.Write("is"); break;
                case RelationalOp.IsNot: writer.Write("is not"); break;
                case RelationalOp.In: writer.Write("in"); break;
                case RelationalOp.NotIn: writer.Write("not in"); break;
                default:
                    throw new ArgumentException(SR.InvalidRelationalOp, nameof(n));
            }
        }

        public virtual void WriteRelationalOpValuePair(RelationalOpValuePair n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(" ");
            WriteRelationalOp(n.Op, writer);
            writer.Write(" ");
            WriteExpression(n.Value, writer, RelationalExpressionOpPrecedence + 1);
        }

        public virtual void WriteComprehensionFilter(ComprehensionFilter n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(" if ");
            WriteExpression(n.Condition, writer);
        }

        public virtual void WriteComprehensionFilterList(ComprehensionFilterList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            foreach (ComprehensionFilter item in n.Items)
                WriteComprehensionFilter(item, writer);
        }

        public virtual void WriteComprehension(Comprehension n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsAsync)
                writer.Write(" async");
            writer.Write(" for ");
            WriteExpression(n.Enumerator, writer);
            writer.Write(" in ");
            WriteExpression(n.Enumerable, writer);
            WriteComprehensionFilterList(n.Filters, writer);
        }

        public virtual void WriteComprehensionList(ComprehensionList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            foreach (Comprehension item in n.Items)
                WriteComprehension(item, writer);
        }

        public virtual void WriteIndexSubscript(IndexSubscript n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteRangeSubscript(RangeSubscript n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Lower != null)
                WriteExpression(n.Lower, writer);
            writer.Write(":");
            if (n.Upper != null)
                WriteExpression(n.Upper, writer);
            if (n.Step != null)
            {
                writer.Write(":");
                WriteExpression(n.Step, writer);
            }
        }

        public virtual void WriteInclusiveRangeSubscript(InclusiveRangeSubscript n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            bool needSpace = n.Lower.IsInteger || n.Upper.IsInteger;
            WriteExpression(n.Lower, writer);
            if (needSpace)
                writer.Write(" ");
            writer.Write("..");
            if (needSpace)
                writer.Write(" ");
            WriteExpression(n.Upper, writer);
            if (n.Step != null)
            {
                if (needSpace)
                    writer.Write(" ");
                writer.Write("..");
                if (needSpace)
                    writer.Write(" ");
                WriteExpression(n.Step, writer);
            }
        }

        public virtual void WriteExtendedSubscript(ExtendedSubscript n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Dimensions.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteSubscript(n.Dimensions[i], writer);
            }
        }

        public virtual void WriteSubscriptList(SubscriptList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteSubscript(n.Items[i], writer);
            }
            if (n.HasTrailingComma)
                writer.Write(",");
        }

        public virtual void WriteNullLiteral(object n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("null");
        }

        public virtual void WriteNullLiteral(NullLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteNullLiteral(null as object, writer);
        }

        public virtual void WriteNullExpression(NullExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteNullLiteral(n.Value, writer);
        }

        public virtual void WriteBooleanLiteral(bool n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(n ? "true" : "false");
        }

        public virtual void WriteBooleanLiteral(BooleanLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteBooleanLiteral(n.Value, writer);
        }

        public virtual void WriteBooleanExpression(BooleanExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteBooleanLiteral(n.Value, writer);
        }

        public virtual void WriteIntegerLiteral(BigInteger n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(n.ToString(CultureInfo.InvariantCulture));
        }

        public virtual void WriteIntegerLiteral(IntegerLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIntegerLiteral(n.Value, writer);
        }

        public virtual void WriteIntegerExpression(IntegerExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIntegerLiteral(n.Value, writer);
        }

        public virtual void WriteFloatLiteral(double n, IndentedWriter writer, bool allowAsInt)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (double.IsPositiveInfinity(n))
                writer.Write("inf");
            else if (double.IsNegativeInfinity(n))
                writer.Write("-inf");
            else if (double.IsNaN(n))
                writer.Write("nan");
            else
            {
                string str = n.ToString(CultureInfo.InvariantCulture).ToLowerInvariant();
                str = str.Replace("e+", "e");
                if (!allowAsInt && str.IndexOfAny(new[] { '.', 'e' }) == -1)
                    writer.Write("{0}.0", str);
                else
                    writer.Write(str);
            }
        }

        public virtual void WriteFloatLiteral(double n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteFloatLiteral(n, writer, false);
        }

        public virtual void WriteFloatLiteral(FloatLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteFloatLiteral(n.Value, writer);
        }

        public virtual void WriteFloatExpression(FloatExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteFloatLiteral(n.Value, writer);
        }

        public virtual void WriteComplexLiteral(Complex n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Imaginary == 0.0)
                WriteFloatLiteral(n.Real, writer, false);
            else if (n.Real == 0.0)
            {
                WriteFloatLiteral(n.Imaginary, writer, true);
                writer.Write("j");
            }
            else if (n.Imaginary < 0.0)
            {
                writer.Write("(");
                WriteFloatLiteral(n.Real, writer, true);
                writer.Write("-");
                WriteFloatLiteral(-n.Imaginary, writer, true);
                writer.Write("j)");
            }
            else
            {
                writer.Write("(");
                WriteFloatLiteral(n.Real, writer, true);
                writer.Write("+");
                WriteFloatLiteral(n.Imaginary, writer, true);
                writer.Write("j)");
            }
        }

        public virtual void WriteComplexLiteral(ComplexLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteComplexLiteral(n.Value, writer);
        }

        public virtual void WriteComplexExpression(ComplexExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteComplexLiteral(n.Value, writer);
        }

        public virtual string Escape(int c, char delimiter)
        {
            if (c < CharExtensions.MinChar || c > CharExtensions.MaxChar)
                throw new ArgumentOutOfRangeException(nameof(c), SR.InvalidUnicodeCodepoint);
            if (delimiter != '\'' && delimiter != '"')
                throw new ArgumentException(SR.DelimiterMustBeSingleOrDoubleQuote, nameof(delimiter));
            switch (c)
            {
                case '\a': return "\\a";
                case '\b': return "\\b";
                case '\t': return "\\t";
                case '\n': return "\\n";
                case '\v': return "\\v";
                case '\f': return "\\f";
                case '\r': return "\\r";
                case '\\': return "\\\\";
                case '\'': return delimiter == '\'' ? "\\'" : "'";
                case '"': return delimiter == '"' ? "\\\"" : "\"";
                default:
                    if (' ' <= c && c <= 0x7E)
                        return "" + (char)c;
                    else if (0 <= c && c <= 0xFF)
                        return string.Format("\\x{0:x2}", c);
                    else if (0 <= c && c <= 0xFFFF)
                        return string.Format("\\u{0:x4}", c);
                    else
                        return string.Format("\\U{0:x8}", c);
            }
        }

        public virtual void WriteCharLiteral(int n, IndentedWriter writer)
        {
            if (n < CharExtensions.MinChar || n > CharExtensions.MaxChar)
                throw new ArgumentOutOfRangeException(nameof(n), SR.InvalidUnicodeCodepoint);
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const char delim = '\'';
            writer.Write(delim);
            writer.Write(Escape(n, delim));
            writer.Write(delim);
        }

        public virtual void WriteCharLiteral(CharLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteCharLiteral(n.Value, writer);
        }

        public virtual void WriteStringLiteral(string n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const char delim = '"';
            writer.Write(delim);
            foreach (int c in n.EnumCodepoints())
                writer.Write(Escape(c, delim));
            writer.Write(delim);
        }

        public virtual void WriteQuoteStringLiteral(string n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const char delim = '\'';
            writer.Write(delim);
            foreach (int c in n.EnumCodepoints())
                writer.Write(Escape(c, delim));
            writer.Write(delim);
        }

        public virtual void WriteStringLiteral(StringLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStringLiteral(n.Value, writer);
        }

        public virtual void WriteQuoteStringLiteral(StringLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteQuoteStringLiteral(n.Value, writer);
        }

        public virtual void WriteByteStringLiteral(IEnumerable<byte> n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const char delim = '"';
            writer.Write('b');
            writer.Write(delim);
            foreach (byte c in n)
                writer.Write(Escape(c, delim));
            writer.Write(delim);
        }

        public virtual void WriteQuoteByteStringLiteral(IEnumerable<byte> n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const char delim = '\'';
            writer.Write('b');
            writer.Write(delim);
            foreach (byte c in n)
                writer.Write(Escape(c, delim));
            writer.Write(delim);
        }

        public virtual void WriteByteStringLiteral(ByteStringLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteByteStringLiteral(n.Value, writer);
        }

        public virtual void WriteQuoteByteStringLiteral(ByteStringLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteQuoteByteStringLiteral(n.Value, writer);
        }

        public virtual void WriteStringExpression(StringExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStringLiteral(n.Value, writer);
        }

        public virtual void WriteByteStringExpression(ByteStringExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteByteStringLiteral(n.Value, writer);
        }

        public virtual void WriteQuoteStringExpression(QuoteStringExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteQuoteStringLiteral(n.Value, writer);
        }

        public virtual void WriteQuoteByteStringExpression(QuoteByteStringExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteQuoteByteStringLiteral(n.Value, writer);
        }

        public virtual void WriteStringSeriesExpression(StringSeriesExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Values.Count; i++)
            {
                if (i > 0)
                    writer.Write(" ");
                WriteStringLiteral(n.Values[i], writer);
            }
        }

        public virtual void WriteByteStringSeriesExpression(ByteStringSeriesExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Values.Count; i++)
            {
                if (i > 0)
                    writer.Write(" ");
                WriteByteStringLiteral(n.Values[i], writer);
            }
        }

        public virtual void WriteQuoteStringSeriesExpression(QuoteStringSeriesExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Values.Count; i++)
            {
                if (i > 0)
                    writer.Write(" ");
                WriteQuoteStringLiteral(n.Values[i], writer);
            }
        }

        public virtual void WriteQuoteByteStringSeriesExpression(QuoteByteStringSeriesExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Values.Count; i++)
            {
                if (i > 0)
                    writer.Write(" ");
                WriteQuoteByteStringLiteral(n.Values[i], writer);
            }
        }

        private void WriteFStringItem(Expression n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n.Tag)
            {
                case ExpressionCategory.String:
                case ExpressionCategory.QuoteString:
                case ExpressionCategory.StringSeries:
                case ExpressionCategory.QuoteStringSeries:
                    {
                        StringBuilder sb = new StringBuilder();
                        if (n.IsString)
                            sb.Append(n.AsString.Value.Value);
                        else if (n.IsQuoteString)
                            sb.Append(n.AsQuoteString.Value.Value);
                        else if (n.IsStringSeries)
                            foreach (StringLiteral item in n.AsStringSeries.Values)
                                sb.Append(item.Value);
                        else
                            foreach (StringLiteral item in n.AsQuoteStringSeries.Values)
                                sb.Append(item.Value);
                        sb.Replace("{", "{{");
                        sb.Replace("}", "}}");
                        string value = sb.ToString();
                        writer.Write(value);
                        break;
                    }
                case ExpressionCategory.JoinedString:
                    foreach (Expression item in n.AsJoinedString.Values)
                        WriteFStringItem(item, writer);
                    break;
                case ExpressionCategory.FormattedValue:
                    writer.Write("{");
                    string str = n.AsFormattedValue.Value.ToString(this);
                    if (str.StartsWith("{"))
                        writer.Write(" ");
                    writer.Write(str);
                    if (n.AsFormattedValue.Conversion.HasValue)
                    {
                        switch (n.AsFormattedValue.Conversion.Value)
                        {
                            case 's': writer.Write("!s"); break;
                            case 'r': writer.Write("!r"); break;
                            case 'a': writer.Write("!a"); break;
                            default:
                                AssertionErrorException e = new AssertionErrorException(SR.InvalidConversionCode);
                                e.AddLocation(n.Context);
                                throw e;
                        }
                    }
                    if (n.AsFormattedValue.Format != null)
                    {
                        writer.Write(":");
                        WriteFStringItem(n.AsFormattedValue.Format, writer);
                    }
                    writer.Write("}");
                    break;
                default:
                    {
                        AssertionErrorException e = new AssertionErrorException(SR.UnexpectedFStringItemType);
                        e.AddLocation(n.Context);
                        throw e;
                    }
            }
        }

        private void WriteFString(Expression n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("f");
            using (StringWriter sw = new StringWriter())
            {
                IndentedWriter w = new IndentedWriter(sw);
                WriteFStringItem(n, w);
                string str = sw.ToString();
                WriteStringLiteral(str, writer);
            }
        }

        public virtual void WriteJoinedStringExpression(JoinedStringExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteFString(n, writer);
        }

        public virtual void WriteFormattedValueExpression(FormattedValueExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteFString(n, writer);
        }

        public virtual void WriteNameReferenceExpression(NameReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WriteBuiltinTypeReferenceExpression(BuiltinTypeReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypeExpression(n.Type, writer, PrimaryTypeExpressionOpPrecedence);
        }

        public virtual void WriteTypeReferenceExpression(TypeReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypeExpression(n.Type, writer);
        }

        public virtual void WriteSlotValueReferenceExpression(SlotValueReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("$");
            WriteIntegerLiteral(n.Slot, writer);
        }

        public virtual void WriteSlotContextReferenceExpression(SlotContextReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("@");
            WriteIntegerLiteral(n.Slot, writer);
        }

        public virtual void WriteResultValueReferenceExpression(ResultValueReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("$$");
        }

        public virtual void WriteResultContextReferenceExpression(ResultContextReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("@@");
        }

        public virtual void WriteThisReferenceExpression(ThisReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("this");
        }

        public virtual void WriteBaseReferenceExpression(BaseReferenceExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("base");
        }

        public virtual void WriteEllipsisExpression(EllipsisExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("...");
        }

        public virtual void WriteUnitExpression(UnitExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("()");
        }

        public virtual void WriteEmptyListExpression(EmptyListExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[]");
        }

        public virtual void WriteEmptySetExpression(EmptySetExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{}");
        }

        public virtual void WriteEmptyMapExpression(EmptyMapExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{:}");
        }

        public virtual void WriteGroupExpression(GroupExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(");
            WriteExpression(n.Operand, writer);
            writer.Write(")");
        }

        public virtual void WriteTupleExpression(TupleExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteExpression(n.Elements[i], writer);
            }
            if (n.Elements.Count == 1)
                writer.Write(",");
            writer.Write(")");
        }

        public virtual void WriteRecordExpression(RecordExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(");
            for (int i = 0; i < n.Fields.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteFieldLabelValuePair(n.Fields[i], writer);
            }
            writer.Write(")");
        }

        public virtual void WriteValueTupleExpression(ValueTupleExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("struct(");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteExpression(n.Elements[i], writer);
            }
            writer.Write(")");
        }

        public virtual void WriteValueRecordExpression(ValueRecordExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("struct(");
            for (int i = 0; i < n.Fields.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteFieldLabelValuePair(n.Fields[i], writer);
            }
            writer.Write(")");
        }

        public virtual void WriteListExpression(ListExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteExpression(n.Elements[i], writer);
            }
            writer.Write("]");
        }

        public virtual void WriteSetExpression(SetExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteExpression(n.Elements[i], writer);
            }
            writer.Write("}");
        }

        public virtual void WriteMapExpression(MapExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteMapKeyValuePair(n.Elements[i], writer);
            }
            writer.Write("}");
        }

        public virtual void WriteGeneratorExpression(GeneratorExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(");
            WriteExpression(n.Element, writer);
            WriteComprehensionList(n.Comprehensions, writer);
            writer.Write(")");
        }

        public virtual void WriteListComprehensionExpression(ListComprehensionExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteExpression(n.Element, writer);
            WriteComprehensionList(n.Comprehensions, writer);
            writer.Write("]");
        }

        public virtual void WriteSetComprehensionExpression(SetComprehensionExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteExpression(n.Element, writer);
            WriteComprehensionList(n.Comprehensions, writer);
            writer.Write("}");
        }

        public virtual void WriteMapComprehensionExpression(MapComprehensionExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteExpression(n.Key, writer);
            writer.Write(": ");
            WriteExpression(n.Value, writer);
            WriteComprehensionList(n.Comprehensions, writer);
            writer.Write("}");
        }

        public virtual void WriteAccessExpression(AccessExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            if (n.Operand.IsInteger)
                writer.Write(" ");
            writer.Write(".");
            WriteIdentifier(n.Member, writer);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteNullableAccessExpression(NullableAccessExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            writer.Write("?.");
            WriteIdentifier(n.Member, writer);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteCallExpression(CallExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            WriteArgumentList(n.Arguments, writer);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteSubscriptExpression(SubscriptExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            writer.Write("[");
            WriteSubscriptList(n.Subscripts, writer);
            writer.Write("]");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteNewExpression(NewExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("new ");
            WriteTypeExpression(n.Type, writer);
            WriteArgumentList(n.Arguments, writer);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteDefaultExpression(DefaultExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("default(");
            WriteTypeExpression(n.Type, writer);
            writer.Write(")");
        }

        public virtual void WriteTypeOfExpression(TypeOfExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("typeof(");
            WriteTypeExpression(n.Type, writer);
            writer.Write(")");
        }

        public virtual void WriteNameOfExpression(NameOfExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("nameof(");
            WriteExpression(n.Operand, writer);
            writer.Write(")");
        }

        public virtual void WritePostfixIncrementExpression(PostfixIncrementExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            string str = n.Operand.ToString(this);
            if (str.EndsWith("+"))
                writer.Write(" ");
            writer.Write("++");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WritePostfixDecrementExpression(PostfixDecrementExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            string str = n.Operand.ToString(this);
            if (str.EndsWith("-"))
                writer.Write(" ");
            writer.Write("--");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteEmptyMutableListExpression(EmptyMutableListExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[]!");
        }

        public virtual void WriteEmptyMutableSetExpression(EmptyMutableSetExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{}!");
        }

        public virtual void WriteEmptyMutableMapExpression(EmptyMutableMapExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{:}!");
        }

        public virtual void WriteMutableListExpression(MutableListExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteExpression(n.Elements[i], writer);
            }
            writer.Write("]!");
        }

        public virtual void WriteMutableSetExpression(MutableSetExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteExpression(n.Elements[i], writer);
            }
            writer.Write("}!");
        }

        public virtual void WriteMutableMapExpression(MutableMapExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            for (int i = 0; i < n.Elements.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteMapKeyValuePair(n.Elements[i], writer);
            }
            writer.Write("}!");
        }

        public virtual void WriteMutableListComprehensionExpression(MutableListComprehensionExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteExpression(n.Element, writer);
            WriteComprehensionList(n.Comprehensions, writer);
            writer.Write("]!");
        }

        public virtual void WriteMutableSetComprehensionExpression(MutableSetComprehensionExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteExpression(n.Element, writer);
            WriteComprehensionList(n.Comprehensions, writer);
            writer.Write("}!");
        }

        public virtual void WriteMutableMapComprehensionExpression(MutableMapComprehensionExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteExpression(n.Key, writer);
            writer.Write(": ");
            WriteExpression(n.Value, writer);
            WriteComprehensionList(n.Comprehensions, writer);
            writer.Write("}!");
        }

        public virtual void WriteIsInstanceOfExpression(IsInstanceOfExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = TypeCheckExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            writer.Write(" :? ");
            WriteTypeExpression(n.Type, writer, PrimaryTypeExpressionOpPrecedence);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteAsInstanceOfExpression(AsInstanceOfExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = TypeCheckExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Operand, writer, prec);
            writer.Write(" :?> ");
            WriteTypeExpression(n.Type, writer, PrimaryTypeExpressionOpPrecedence);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteAwaitExpression(AwaitExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = AwaitExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("await ");
            WriteExpression(n.Operand, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WritePowerExpression(PowerExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PowerExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec + 1);
            writer.Write(" ** ");
            WriteExpression(n.Right, writer, prec - 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WritePositiveExpression(PositiveExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnaryExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("+");
            string str = n.Operand.ToString(this);
            if (str.StartsWith("+"))
                writer.Write(" ");
            WriteExpression(n.Operand, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteNegativeExpression(NegativeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnaryExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("-");
            string str = n.Operand.ToString(this);
            if (str.StartsWith("-"))
                writer.Write(" ");
            WriteExpression(n.Operand, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteBitwiseNotExpression(BitwiseNotExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnaryExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("~");
            WriteExpression(n.Operand, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteLogicalNotExpression(LogicalNotExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnaryExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("!");
            WriteExpression(n.Operand, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WritePrefixIncrementExpression(PrefixIncrementExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnaryExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("++");
            string str = n.Operand.ToString(this);
            if (str.StartsWith("+"))
                writer.Write(" ");
            WriteExpression(n.Operand, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WritePrefixDecrementExpression(PrefixDecrementExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnaryExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("--");
            string str = n.Operand.ToString(this);
            if (str.StartsWith("-"))
                writer.Write(" ");
            WriteExpression(n.Operand, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteMultiplyExpression(MultiplyExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = MultiplicativeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" * ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteMatrixMultiplyExpression(MatrixMultiplyExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = MultiplicativeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" @ ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteFloorDivideExpression(FloorDivideExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = MultiplicativeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" // ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteDivideExpression(DivideExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = MultiplicativeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" / ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteModuloExpression(ModuloExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = MultiplicativeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" % ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteAddExpression(AddExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = AdditiveExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" + ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteSubtractExpression(SubtractExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = AdditiveExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" - ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteLeftShiftExpression(LeftShiftExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = ShiftExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" << ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteRightShiftExpression(RightShiftExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = ShiftExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" >> ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteUnsignedRightShiftExpression(UnsignedRightShiftExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = ShiftExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" >>> ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteBitwiseAndExpression(BitwiseAndExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = BitwiseAndExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" & ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteBitwiseXorExpression(BitwiseXorExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = BitwiseXorExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" ^ ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteBitwiseOrExpression(BitwiseOrExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = BitwiseOrExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" | ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteRelationalExpression(RelationalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = RelationalExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, RelationalExpressionOpPrecedence + 1);
            foreach (RelationalOpValuePair pair in n.OpValuePairs)
                WriteRelationalOpValuePair(pair, writer);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteLogicalAndExpression(LogicalAndExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = LogicalAndExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" && ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteLogicalOrExpression(LogicalOrExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = LogicalOrExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Left, writer, prec);
            writer.Write(" || ");
            WriteExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteConditionalExpression(ConditionalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = TestExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteExpression(n.Body, writer, prec + 1);
            writer.Write(" if ");
            WriteExpression(n.Test, writer, prec + 1);
            writer.Write(" else ");
            WriteExpression(n.OrElse, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        protected static bool IsParameterListEmpty(ParameterList n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (n.PositionalOnly.Count > 0)
                return false;
            if (n.Positional.Count > 0)
                return false;
            if (n.ExtraPositional != null)
                return false;
            if (n.KeywordOnly.Count > 0)
                return false;
            if (n.ExtraKeywords != null)
                return false;
            return true;
        }

        protected static bool IsParameterSimple(Parameter n)
        {
            return n == null || n.Type == null && n.Value == null;
        }

        protected static bool IsParameterListSimple(ParameterList n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            foreach (Parameter item in n.PositionalOnly)
                if (!IsParameterSimple(item))
                    return false;
            foreach (Parameter item in n.Positional)
                if (!IsParameterSimple(item))
                    return false;
            if (n.ExtraPositional != null)
                if (!IsParameterSimple(n.ExtraPositional))
                    return false;
            foreach (Parameter item in n.KeywordOnly)
                if (!IsParameterSimple(item))
                    return false;
            if (n.ExtraKeywords != null)
                if (!IsParameterSimple(n.ExtraKeywords))
                    return false;
            return true;
        }

        public virtual void WriteLambdaExpression(LambdaExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = TestExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("lambda");
            if (!IsParameterListEmpty(n.Parameters))
            {
                writer.Write(" ");
                if (IsParameterListSimple(n.Parameters))
                    WriteParameterList(n.Parameters, writer);
                else
                {
                    writer.Write("(");
                    WriteParameterList(n.Parameters, writer);
                    writer.Write(")");
                }
            }
            writer.Write(": ");
            WriteExpression(n.Body, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteYieldFromExpression(YieldFromExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = YieldExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("yield from ");
            WriteExpression(n.Value, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteYieldExpression(YieldExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = YieldExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("yield");
            if (n.Value != null)
            {
                writer.Write(" ");
                WriteExpression(n.Value, writer, prec + 1);
            }
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteYieldBreakExpression(YieldBreakExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = YieldExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("yield break");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteUnpackExpression(UnpackExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnpackExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            writer.Write("*");
            WriteExpression(n.Operand, writer, BitwiseOrExpressionOpPrecedence);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteFieldLabelTypePair(FieldLabelTypePair n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
        }

        public virtual void WriteInt8TypeExpression(Int8TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int8");
        }

        public virtual void WriteInt16TypeExpression(Int16TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int16");
        }

        public virtual void WriteInt32TypeExpression(Int32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int32");
        }

        public virtual void WriteInt64TypeExpression(Int64TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int64");
        }

        public virtual void WriteUInt8TypeExpression(UInt8TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint8");
        }

        public virtual void WriteUInt16TypeExpression(UInt16TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint16");
        }

        public virtual void WriteUInt32TypeExpression(UInt32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint32");
        }

        public virtual void WriteUInt64TypeExpression(UInt64TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint64");
        }

        public virtual void WriteFloat32TypeExpression(Float32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float32");
        }

        public virtual void WriteFloat64TypeExpression(Float64TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float64");
        }

        public virtual void WriteChar8TypeExpression(Char8TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("char8");
        }

        public virtual void WriteChar16TypeExpression(Char16TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("char16");
        }

        public virtual void WriteChar32TypeExpression(Char32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("char32");
        }

        public virtual void WriteSByteTypeExpression(SByteTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("sbyte");
        }

        public virtual void WriteShortTypeExpression(ShortTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("short");
        }

        public virtual void WriteIntTypeExpression(IntTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int");
        }

        public virtual void WriteLongTypeExpression(LongTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("long");
        }

        public virtual void WriteByteTypeExpression(ByteTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("byte");
        }

        public virtual void WriteUShortTypeExpression(UShortTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ushort");
        }

        public virtual void WriteUIntTypeExpression(UIntTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint");
        }

        public virtual void WriteULongTypeExpression(ULongTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ulong");
        }

        public virtual void WriteIntPtrTTypeExpression(IntPtrTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("intptr_t");
        }

        public virtual void WriteUIntPtrTTypeExpression(UIntPtrTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ptrdiff_t");
        }

        public virtual void WriteSizeTTypeExpression(SizeTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("size_t");
        }

        public virtual void WriteSSizeTTypeExpression(SSizeTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ssize_t");
        }

        public virtual void WritePtrDiffTTypeExpression(PtrDiffTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ptrdiff_t");
        }

        public virtual void WriteFloatTypeExpression(FloatTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float");
        }

        public virtual void WriteDoubleTypeExpression(DoubleTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("double");
        }

        public virtual void WriteDecimalTypeExpression(DecimalTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("decimal");
        }

        public virtual void WriteBoolTypeExpression(BoolTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("bool");
        }

        public virtual void WriteCharTypeExpression(CharTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("char");
        }

        public virtual void WriteStringTypeExpression(StringTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("string");
        }

        public virtual void WriteObjectTypeExpression(ObjectTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("object");
        }

        public virtual void WriteDynamicTypeExpression(DynamicTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("dynamic");
        }

        public virtual void WriteUnitTypeExpression(UnitTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("()");
        }

        public virtual void WriteTupleTypeExpression(TupleTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(");
            for (int i = 0; i < n.ElementTypes.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteTypeExpression(n.ElementTypes[i], writer);
            }
            if (n.ElementTypes.Count == 1)
                writer.Write(",");
            writer.Write(")");
        }

        public virtual void WriteRecordTypeExpression(RecordTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(");
            for (int i = 0; i < n.Fields.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteFieldLabelTypePair(n.Fields[i], writer);
            }
            writer.Write(")");
        }

        public virtual void WriteValueTupleTypeExpression(ValueTupleTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("struct(");
            for (int i = 0; i < n.ElementTypes.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteTypeExpression(n.ElementTypes[i], writer);
            }
            writer.Write(")");
        }

        public virtual void WriteValueRecordTypeExpression(ValueRecordTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("struct(");
            for (int i = 0; i < n.Fields.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteFieldLabelTypePair(n.Fields[i], writer);
            }
            writer.Write(")");
        }

        public virtual void WriteListTypeExpression(ListTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("]");
        }

        public virtual void WriteSetTypeExpression(SetTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("}");
        }

        public virtual void WriteMapTypeExpression(MapTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.KeyType, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.ValueType, writer);
            writer.Write("}");
        }

        public virtual void WriteNameReferenceTypeExpression(NameReferenceTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WriteGlobalNameReferenceTypeExpression(GlobalNameReferenceTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("global::");
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WriteAccessTypeExpression(AccessTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixTypeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteTypeExpression(n.Operand, writer, prec);
            writer.Write(".");
            WriteIdentifier(n.Member, writer);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteUnboundedGenericTypeExpression(UnboundedGenericTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixTypeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteTypeExpression(n.Operand, writer, prec);
            writer.Write("[");
            for (int i = 1; i < n.Arity; i++)
                writer.Write(",");
            writer.Write("]");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteBoundedGenericTypeExpression(BoundedGenericTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixTypeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteTypeExpression(n.Operand, writer, prec);
            writer.Write("[");
            for (int i = 0; i < n.Arguments.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteTypeExpression(n.Arguments[i], writer);
            }
            writer.Write("]");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteNonNegativeInt8TypeExpression(NonNegativeInt8TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int8*");
        }

        public virtual void WriteNonNegativeInt16TypeExpression(NonNegativeInt16TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int16*");
        }

        public virtual void WriteNonNegativeInt32TypeExpression(NonNegativeInt32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int32*");
        }

        public virtual void WriteNonNegativeInt64TypeExpression(NonNegativeInt64TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int64*");
        }

        public virtual void WriteNonNegativeFloat32TypeExpression(NonNegativeFloat32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float32*");
        }

        public virtual void WriteNonNegativeFloat64TypeExpression(NonNegativeFloat64TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float64*");
        }

        public virtual void WriteNonNegativeSByteTypeExpression(NonNegativeSByteTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("sbyte*");
        }

        public virtual void WriteNonNegativeShortTypeExpression(NonNegativeShortTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("short*");
        }

        public virtual void WriteNonNegativeIntTypeExpression(NonNegativeIntTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int*");
        }

        public virtual void WriteNonNegativeLongTypeExpression(NonNegativeLongTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("long*");
        }

        public virtual void WriteNonNegativeIntPtrTTypeExpression(NonNegativeIntPtrTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("intptr_t*");
        }

        public virtual void WriteNonNegativeSSizeTTypeExpression(NonNegativeSSizeTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ssize_t*");
        }

        public virtual void WriteNonNegativePtrDiffTTypeExpression(NonNegativePtrDiffTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ptrdiff_t*");
        }

        public virtual void WriteNonNegativeFloatTypeExpression(NonNegativeFloatTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float*");
        }

        public virtual void WriteNonNegativeDoubleTypeExpression(NonNegativeDoubleTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("double*");
        }

        public virtual void WriteNonNegativeDecimalTypeExpression(NonNegativeDecimalTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("decimal*");
        }

        public virtual void WritePositiveInt8TypeExpression(PositiveInt8TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int8+");
        }

        public virtual void WritePositiveInt16TypeExpression(PositiveInt16TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int16+");
        }

        public virtual void WritePositiveInt32TypeExpression(PositiveInt32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int32+");
        }

        public virtual void WritePositiveInt64TypeExpression(PositiveInt64TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int64+");
        }

        public virtual void WritePositiveFloat32TypeExpression(PositiveFloat32TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float32+");
        }

        public virtual void WritePositiveFloat64TypeExpression(PositiveFloat64TypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float64+");
        }

        public virtual void WritePositiveSByteTypeExpression(PositiveSByteTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("sbyte+");
        }

        public virtual void WritePositiveShortTypeExpression(PositiveShortTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("short+");
        }

        public virtual void WritePositiveIntTypeExpression(PositiveIntTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int+");
        }

        public virtual void WritePositiveLongTypeExpression(PositiveLongTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("long+");
        }

        public virtual void WritePositiveIntPtrTTypeExpression(PositiveIntPtrTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("intptr_t+");
        }

        public virtual void WritePositiveSSizeTTypeExpression(PositiveSSizeTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ssize_t+");
        }

        public virtual void WritePositiveDiffTTypeExpression(PositiveDiffTTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ptrdiff_t+");
        }

        public virtual void WritePositiveFloatTypeExpression(PositiveFloatTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float+");
        }

        public virtual void WritePositiveDoubleTypeExpression(PositiveDoubleTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("double+");
        }

        public virtual void WritePositiveDecimalTypeExpression(PositiveDecimalTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("decimal+");
        }

        public virtual void WriteMutableListTypeExpression(MutableListTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("]!");
        }

        public virtual void WriteMutableSetTypeExpression(MutableSetTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("}!");
        }

        public virtual void WriteMutableMapTypeExpression(MutableMapTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.KeyType, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.ValueType, writer);
            writer.Write("}!");
        }

        public virtual void WriteNonEmptyListTypeExpression(NonEmptyListTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("]+");
        }

        public virtual void WriteNonEmptySetTypeExpression(NonEmptySetTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("}+");
        }

        public virtual void WriteNonEmptyMapTypeExpression(NonEmptyMapTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.KeyType, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.ValueType, writer);
            writer.Write("}+");
        }

        public virtual void WriteNonEmptyMutableListTypeExpression(NonEmptyMutableListTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("]!+");
        }

        public virtual void WriteNonEmptyMutableSetTypeExpression(NonEmptyMutableSetTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.ElementType, writer);
            writer.Write("}!+");
        }

        public virtual void WriteNonEmptyMutableMapTypeExpression(NonEmptyMutableMapTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("{");
            WriteTypeExpression(n.KeyType, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.ValueType, writer);
            writer.Write("}!+");
        }

        public virtual void WriteNullableTypeExpression(NullableTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixTypeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteTypeExpression(n.OperandType, writer, prec);
            writer.Write("?");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteUnionTypeExpression(UnionTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = UnionTypeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            for (int i = 0; i < n.ElementTypes.Count; i++)
            {
                if (i > 0)
                    writer.Write(" | ");
                WriteTypeExpression(n.ElementTypes[i], writer, prec);
            }
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteFunctionTypeExpression(FunctionTypeExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = FunctionTypeExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteTypeExpression(n.ArgumentType, writer, prec + 1);
            writer.Write(" -> ");
            WriteTypeExpression(n.ResultType, writer, prec);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteImportBinding(ImportBinding n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Name.Count; i++)
            {
                if (i > 0)
                    writer.Write(".");
                WriteIdentifier(n.Name[i], writer);
            }
            if (n.Alias != null)
            {
                writer.Write(" as ");
                WriteIdentifier(n.Alias, writer);
            }
        }

        public virtual void WriteFromImportBinding(FromImportBinding n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.Alias != null)
            {
                writer.Write(" as ");
                WriteIdentifier(n.Alias, writer);
            }
        }

        public virtual void WriteWithBinding(WithBinding n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Value, writer);
            if (n.Variables != null)
            {
                writer.Write(" as ");
                WriteExpression(n.Variables, writer);
            }
        }

        public virtual void WriteElseIfBranch(ElseIfBranch n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("elif ");
            WriteExpression(n.Test, writer);
            WriteStatement(n.Body, writer);
        }

        public virtual void WriteSwitchCaseClause(SwitchCaseClause n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("case ");
            WriteExpression(n.Value, writer);
            WriteStatement(n.Body, writer);
        }

        public virtual void WriteExceptionHandler(ExceptionHandler n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("catch");
            if (n.Type != null)
            {
                writer.Write(" ");
                WriteTypeExpression(n.Type, writer);
                if (n.Name != null)
                {
                    writer.Write(" as ");
                    WriteIdentifier(n.Name, writer);
                }
            }
            WriteStatement(n.Body, writer);
        }

        public virtual void WriteDottedNameDecorator(DottedNameDecorator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("@");
            for (int i = 0; i < n.Names.Count; i++)
            {
                if (i > 0)
                    writer.Write(".");
                WriteIdentifier(n.Names[i], writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteDottedNameCallDecorator(DottedNameCallDecorator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("@");
            for (int i = 0; i < n.Names.Count; i++)
            {
                if (i > 0)
                    writer.Write(".");
                WriteIdentifier(n.Names[i], writer);
            }
            WriteArgumentList(n.Arguments, writer);
            writer.Write("\n");
        }

        public virtual void WriteDecoratorList(DecoratorList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            foreach (Decorator item in n.Items)
                WriteDecorator(item, writer);
        }

        public virtual void WriteFunctionDeclaration(FunctionDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDecoratorList(n.Decorators, writer);
            if (n.IsAsync)
                writer.Write("async ");
            writer.Write("def ");
            WriteIdentifier(n.Name, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            WriteStatement(n.Body, writer);
        }

        public virtual void WriteClassDeclaration(ClassDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDecoratorList(n.Decorators, writer);
            writer.Write("class ");
            WriteIdentifier(n.Name, writer);
            if (n.Arguments.Items.Count > 0)
                WriteArgumentList(n.Arguments, writer);
            WriteStatement(n.Body, writer);
        }

        public virtual void WriteGrammarDeclaration(GrammarDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDecoratorList(n.Decorators, writer);
            writer.Write("grammar ");
            WriteIdentifier(n.Name, writer);
            if (n.Arguments.Items.Count > 0)
                WriteArgumentList(n.Arguments, writer);
            writer.Write(":\n");
            writer.OpenBlock();
            int output = 0;
            if (n.Directives.Items.Count > 0)
            {
                WriteDirectiveDeclaration(n.Directives, writer);
                output++;
            }
            if (n.Types.Declarators.Count > 0)
            {
                if (output > 0)
                    writer.Write("\n");
                WriteTypeDeclaration(n.Types, writer);
                output++;
            }
            if (n.SyntacticDeclaration.Declarators.Count > 0)
            {
                if (output > 0)
                    writer.Write("\n");
                writer.Write("%%\n\n");
                WriteSyntacticDeclaration(n.SyntacticDeclaration, writer);
                output++;
            }
            if (n.LexicalDeclaration.Declarators.Count > 0)
            {
                if (output > 0)
                    writer.Write("\n");
                if (n.SyntacticDeclaration.Declarators.Count == 0)
                    writer.Write("%%\n\n");
                writer.Write("%%\n\n");
                WriteLexicalDeclaration(n.LexicalDeclaration, writer);
                output++;
            }
            if (output == 0)
                writer.Write("pass\n");
            writer.CloseBlock();
        }

        public virtual void WriteGrammarFragment(GrammarFragment n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            int output = 0;
            if (n.Directives.Items.Count > 0)
            {
                WriteDirectiveDeclaration(n.Directives, writer);
                output++;
            }
            if (n.Types.Declarators.Count > 0)
            {
                if (output > 0)
                    writer.Write("\n");
                WriteTypeDeclaration(n.Types, writer);
                output++;
            }
            if (n.SyntacticDeclaration.Declarators.Count > 0)
            {
                if (output > 0)
                    writer.Write("\n");
                writer.Write("%%\n\n");
                WriteSyntacticDeclaration(n.SyntacticDeclaration, writer);
                output++;
            }
            if (n.LexicalDeclaration.Declarators.Count > 0)
            {
                if (output > 0)
                    writer.Write("\n");
                if (n.SyntacticDeclaration.Declarators.Count == 0)
                    writer.Write("%%\n\n");
                writer.Write("%%\n\n");
                WriteLexicalDeclaration(n.LexicalDeclaration, writer);
            }
        }

        public virtual void WritePassStatement(PassStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("pass");
        }

        public virtual void WriteBreakStatement(BreakStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("break");
        }

        public virtual void WriteContinueStatement(ContinueStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("continue");
        }

        public virtual void WriteReturnStatement(ReturnStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("return");
            if (n.Value != null)
            {
                writer.Write(" ");
                WriteExpression(n.Value, writer);
            }
        }

        public virtual void WriteThrowStatement(ThrowStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("throw");
            if (n.Exception != null)
            {
                writer.Write(" ");
                WriteExpression(n.Exception, writer);
            }
            if (n.Cause != null)
            {
                writer.Write(" from ");
                WriteExpression(n.Cause, writer);
            }
        }

        public virtual void WriteAssertStatement(AssertStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("assert ");
            WriteExpression(n.Test, writer);
            if (n.Message != null)
            {
                writer.Write(", ");
                WriteExpression(n.Message, writer);
            }
        }

        public virtual void WriteDeleteStatement(DeleteStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("del");
            for (int i = 0; i < n.Targets.Count; i++)
            {
                writer.Write(i == 0 ? " " : ", ");
                WriteExpression(n.Targets[i], writer);
            }
        }

        public virtual void WriteGlobalStatement(GlobalStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("global");
            for (int i = 0; i < n.Names.Count; i++)
            {
                writer.Write(i == 0 ? " " : ", ");
                WriteIdentifier(n.Names[i], writer);
            }
        }

        public virtual void WriteNonlocalStatement(NonlocalStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("nonlocal");
            for (int i = 0; i < n.Names.Count; i++)
            {
                writer.Write(i == 0 ? " " : ", ");
                WriteIdentifier(n.Names[i], writer);
            }
        }

        public virtual void WriteImportStatement(ImportStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("import");
            for (int i = 0; i < n.Bindings.Count; i++)
            {
                writer.Write(i == 0 ? " " : ", ");
                WriteImportBinding(n.Bindings[i], writer);
            }
        }

        public virtual void WriteFromImportStatement(FromImportStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("from ");
            if (n.Level != null)
                for (int i = 0; i < n.Level.Value; i++)
                    writer.Write(".");
            for (int i = 0; i < n.Module.Count; i++)
            {
                if (i > 0)
                    writer.Write(".");
                WriteIdentifier(n.Module[i], writer);
            }
            writer.Write(" import");
            for (int i = 0; i < n.Bindings.Count; i++)
            {
                writer.Write(i == 0 ? " " : ", ");
                WriteFromImportBinding(n.Bindings[i], writer);
            }
        }

        public virtual void WriteFromImportAllStatement(FromImportAllStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("from ");
            if (n.Level != null)
                for (int i = 0; i < n.Level.Value; i++)
                    writer.Write(".");
            for (int i = 0; i < n.Module.Count; i++)
            {
                if (i > 0)
                    writer.Write(".");
                WriteIdentifier(n.Module[i], writer);
            }
            writer.Write(" import ");
            writer.Write("*");
        }

        public virtual void WriteLetStatement(LetStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("let ");
            WriteIdentifier(n.Variable, writer);
            if (n.Type != null)
            {
                writer.Write(": ");
                WriteTypeExpression(n.Type, writer);
            }
            writer.Write(" = ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteVarStatement(VarStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("var ");
            WriteIdentifier(n.Variable, writer);
            if (n.Type != null)
            {
                writer.Write(": ");
                WriteTypeExpression(n.Type, writer);
            }
            writer.Write(" = ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteConstStatement(ConstStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("const ");
            WriteIdentifier(n.Variable, writer);
            if (n.Type != null)
            {
                writer.Write(": ");
                WriteTypeExpression(n.Type, writer);
            }
            writer.Write(" = ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteExprStatement(ExprStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteAssignStatement(AssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Targets.Count; i++)
            {
                if (i > 0)
                    writer.Write(" = ");
                WriteExpression(n.Targets[i], writer);
            }
            writer.Write(" = ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteAnnotatedAssignStatement(AnnotatedAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (!n.IsSimple && n.Target.IsNameReference)
                writer.Write("(");
            WriteExpression(n.Target, writer);
            if (!n.IsSimple && n.Target.IsNameReference)
                writer.Write(")");
            if (n.Value == null)
                writer.Write(" ");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            if (n.Value != null)
            {
                writer.Write(" = ");
                WriteExpression(n.Value, writer);
            }
        }

        public virtual void WriteAddAssignStatement(AddAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" += ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteSubtractAssignStatement(SubtractAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" -= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteMultiplyAssignStatement(MultiplyAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" *= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteMatrixMultiplyAssignStatement(MatrixMultiplyAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" @= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteFloorDivideAssignStatement(FloorDivideAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" //= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteDivideAssignStatement(DivideAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" /= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteModuloAssignStatement(ModuloAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" %= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WritePowerAssignStatement(PowerAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" **= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteLeftShiftAssignStatement(LeftShiftAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" <<= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteRightShiftAssignStatement(RightShiftAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" >>= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteUnsignedRightShiftAssignStatement(UnsignedRightShiftAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" >>>= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteBitwiseAndAssignStatement(BitwiseAndAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" &= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteBitwiseXorAssignStatement(BitwiseXorAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" ^= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteBitwiseOrAssignStatement(BitwiseOrAssignStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Target, writer);
            writer.Write(" |= ");
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteSequenceStatement(SequenceStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write("; ");
                WriteStatement(n.Items[i], writer);
            }
        }

        public virtual void WriteSimpleStatement(SimpleStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStatement(n.Body, writer);
            writer.Write("\n");
        }

        public virtual void WriteBlockStatement(BlockStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("\n");
            writer.OpenBlock();
            if (n.Body.Count <= 0)
                writer.Write("pass\n");
            else
                foreach (Statement item in n.Body)
                    WriteStatement(item, writer);
            writer.CloseBlock();
        }

        public virtual void WriteSuiteStatement(SuiteStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(":");
            if (!n.IsCompound)
                writer.Write(" ");
            WriteStatement(n.Body, writer);
        }

        public virtual void WriteWithStatement(WithStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsAsync)
                writer.Write("async ");
            writer.Write("with ");
            for (int i = 0; i < n.Bindings.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteWithBinding(n.Bindings[i], writer);
            }
            WriteStatement(n.Body, writer);
        }

        public virtual void WriteForStatement(ForStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsAsync)
                writer.Write("async ");
            writer.Write("for ");
            WriteExpression(n.Enumerator, writer);
            writer.Write(" in ");
            WriteExpression(n.Enumerable, writer);
            WriteStatement(n.Body, writer);
            if (n.OrElse != null)
            {
                writer.Write("else");
                WriteStatement(n.OrElse, writer);
            }
        }

        public virtual void WriteWhileStatement(WhileStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("while ");
            WriteExpression(n.Test, writer);
            WriteStatement(n.Body, writer);
            if (n.OrElse != null)
            {
                writer.Write("else");
                WriteStatement(n.OrElse, writer);
            }
        }

        public virtual void WriteIfStatement(IfStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("if ");
            WriteExpression(n.Test, writer);
            WriteStatement(n.Body, writer);
            foreach (ElseIfBranch item in n.ElseIfBranches)
                WriteElseIfBranch(item, writer);
            if (n.OrElse != null)
            {
                writer.Write("else");
                WriteStatement(n.OrElse, writer);
            }
        }

        public virtual void WriteTryStatement(TryStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("try");
            WriteStatement(n.Body, writer);
            foreach (ExceptionHandler item in n.Handlers)
                WriteExceptionHandler(item, writer);
            if (n.OrElse != null)
            {
                writer.Write("else");
                WriteStatement(n.OrElse, writer);
            }
            if (n.OrElse != null)
            {
                writer.Write("finally");
                WriteStatement(n.FinalBody, writer);
            }
        }

        public virtual void WriteSwitchStatement(SwitchStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("switch ");
            WriteExpression(n.Value, writer);
            writer.Write(":\n");
            writer.OpenBlock();
            foreach (SwitchCaseClause clause in n.Clauses)
                WriteSwitchCaseClause(clause, writer);
            if (n.DefaultActions != null)
            {
                writer.Write("default");
                WriteStatement(n.DefaultActions, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteFunctionStatement(FunctionStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteFunctionDeclaration(n.Declaration, writer);
        }

        public virtual void WriteClassStatement(ClassStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteClassDeclaration(n.Declaration, writer);
        }

        public virtual void WriteGrammarStatement(GrammarStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteGrammarDeclaration(n.Declaration, writer);
        }

        public virtual void WriteEnumTypeStatement(EnumTypeStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteEnumTypeDeclarator(n.Declarator, writer);
        }

        public virtual void WriteStructTypeStatement(StructTypeStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStructTypeDeclarator(n.Declarator, writer);
        }

        public virtual void WriteUnionTypeStatement(UnionTypeStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteUnionTypeDeclarator(n.Declarator, writer);
        }

        public virtual void WriteVisitorTypeStatement(VisitorTypeStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteVisitorTypeDeclarator(n.Declarator, writer);
        }

        public virtual void WriteInterfaceTypeStatement(InterfaceTypeStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteInterfaceDeclarator(n.Declarator, writer);
        }

        public virtual void WriteClassTypeStatement(ClassTypeStatement n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteClassDeclarator(n.Declarator, writer);
        }

        public virtual void WriteFastSemanticAction(FastSemanticAction n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("=> ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteFullSemanticAction(FullSemanticAction n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("=>");
            WriteStatement(n.Actions, writer);
        }

        public virtual void WriteExpressionProgramDescription(ExpressionProgramDescription n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExpression(n.Value, writer);
        }

        public virtual void WriteSegmentProgramDescription(SegmentProgramDescription n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            foreach (Statement item in n.Body)
                WriteStatement(item, writer);
        }

        public virtual void WriteModuleProgramDescription(ModuleProgramDescription n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            foreach (Statement item in n.Body)
                WriteStatement(item, writer);
        }

        public virtual void WriteGrammarProgramDescription(GrammarProgramDescription n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteGrammarFragment(n.Body, writer);
        }

        public virtual void WriteEnumItemDeclarator(EnumItemDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Names.Count; i++)
            {
                if (i > 0)
                    writer.Write(" ");
                WriteIdentifier(n.Names[i], writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteStructFieldDeclarator(StructFieldDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
        }

        public virtual void WriteUnionCaseDeclarator(UnionCaseDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.Fields.Count > 0)
            {
                writer.Write(" (");
                for (int i = 0; i < n.Fields.Count; i++)
                {
                    if (i > 0)
                        writer.Write(", ");
                    WriteStructFieldDeclarator(n.Fields[i], writer);
                }
                writer.Write(")");
            }
            if (n.Subcases == null)
                writer.Write("\n");
            else
            {
                writer.Write(":\n");
                writer.OpenBlock();
                WriteUnionCaseDeclaratorSuite(n.Subcases, writer);
                writer.CloseBlock();
            }
        }

        public virtual void WriteUnionCaseDeclaratorSuite(UnionCaseDeclaratorSuite n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            foreach (UnionCaseDeclarator item in n.Cases)
                WriteUnionCaseDeclarator(item, writer);
            if (n.PrefixFields.Count > 0)
            {
                writer.Write("attributes (");
                for (int i = 0; i < n.PrefixFields.Count; i++)
                {
                    if (i > 0)
                        writer.Write(", ");
                    WriteStructFieldDeclarator(n.PrefixFields[i], writer);
                }
                writer.Write(")\n");
            }
            if (n.PostfixFields.Count > 0)
            {
                writer.Write("attributes! (");
                for (int i = 0; i < n.PostfixFields.Count; i++)
                {
                    if (i > 0)
                        writer.Write(", ");
                    WriteStructFieldDeclarator(n.PostfixFields[i], writer);
                }
                writer.Write(")\n");
            }
        }

        public virtual void WriteEventInterfaceMemberDeclarator(EventInterfaceMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("event ");
            WriteIdentifier(n.Name, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WritePropertyInterfaceMemberDeclarator(PropertyInterfaceMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteIndexerInterfaceMemberDeclarator(IndexerInterfaceMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("this[");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            if (n.IsMutable)
                writer.Write("!");
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteMethodInterfaceMemberDeclarator(MethodInterfaceMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteClassMemberAccessibility(ClassMemberAccessibility n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n)
            {
                case ClassMemberAccessibility.Public: writer.Write("public"); break;
                case ClassMemberAccessibility.Protected: writer.Write("protected"); break;
                case ClassMemberAccessibility.Private: writer.Write("private"); break;
                case ClassMemberAccessibility.Internal: writer.Write("internal"); break;
                case ClassMemberAccessibility.InternalProtected: writer.Write("internal protected"); break;
                case ClassMemberAccessibility.PrivateProtected: writer.Write("private protected"); break;
                case ClassMemberAccessibility.NewPublic: writer.Write("new public"); break;
                case ClassMemberAccessibility.NewProtected: writer.Write("new protected"); break;
                case ClassMemberAccessibility.NewPrivate: writer.Write("new private"); break;
                case ClassMemberAccessibility.NewInternal: writer.Write("new internal"); break;
                case ClassMemberAccessibility.NewInternalProtected: writer.Write("new internal protected"); break;
                case ClassMemberAccessibility.NewPrivateProtected: writer.Write("new private protected"); break;
                case ClassMemberAccessibility.New: writer.Write("new"); break;
                default:
                    throw new ArgumentException(SR.InvalidClassMemberAccessibility, nameof(n));
            }
        }

        public virtual void WriteClassMemberVirtualModifier(ClassMemberVirtualModifier n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n)
            {
                case ClassMemberVirtualModifier.Default: writer.Write("default"); break;
                case ClassMemberVirtualModifier.Override: writer.Write("override"); break;
                case ClassMemberVirtualModifier.Sealed: writer.Write("sealed"); break;
                default:
                    throw new ArgumentException(SR.InvalidClassMemberVirtualModifier, nameof(n));
            }
        }

        public virtual void WriteClassVirtualModifier(ClassVirtualModifier n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n)
            {
                case ClassVirtualModifier.Default: writer.Write("default"); break;
                case ClassVirtualModifier.Sealed: writer.Write("sealed"); break;
                case ClassVirtualModifier.Abstract: writer.Write("abstract"); break;
                case ClassVirtualModifier.Static: writer.Write("static"); break;
                case ClassVirtualModifier.Struct: writer.Write("struct"); break;
                default:
                    throw new ArgumentException(SR.InvalidClassVirtualModifier, nameof(n));
            }
        }

        public virtual void WriteExprClassMethodBody(ExprClassMethodBody n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(" => ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteBlockClassMethodBody(BlockClassMethodBody n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStatement(n.Actions, writer);
        }

        public virtual void WriteFieldClassMemberDeclarator(FieldClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Private)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsStatic)
                writer.Write("static ");
            writer.Write("field ");
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            if (n.Value == null)
                writer.Write(" ");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            if (n.Value != null)
            {
                writer.Write(" = ");
                WriteExpression(n.Value, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteEventClassMemberDeclarator(EventClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsStatic)
                writer.Write("static ");
            writer.Write("event ");
            WriteIdentifier(n.Name, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteEventBlockClassMemberDeclarator(EventBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsStatic)
                writer.Write("static ");
            writer.Write("event ");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("add");
            WriteClassMethodBody(n.Adder, writer);
            if (n.Remover != null)
            {
                writer.Write("remove");
                WriteClassMethodBody(n.Remover, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteVirtualEventClassMemberDeclarator(VirtualEventClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            writer.Write("event ");
            WriteIdentifier(n.Name, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteVirtualEventBlockClassMemberDeclarator(VirtualEventBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            writer.Write("event ");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("add");
            WriteClassMethodBody(n.Adder, writer);
            if (n.Remover != null)
            {
                writer.Write("remove");
                WriteClassMethodBody(n.Remover, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteAbstractEventClassMemberDeclarator(AbstractEventClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("abstract ");
            writer.Write("event ");
            WriteIdentifier(n.Name, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteExplicitEventImplClassMemberDeclarator(ExplicitEventImplClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("event ");
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            WriteIdentifier(n.Name, writer);
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteExplicitEventImplBlockClassMemberDeclarator(ExplicitEventImplBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("event ");
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("add");
            WriteClassMethodBody(n.Adder, writer);
            if (n.Remover != null)
            {
                writer.Write("remove");
                WriteClassMethodBody(n.Remover, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WritePropertyClassMemberDeclarator(PropertyClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsStatic)
                writer.Write("static ");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" => ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WritePropertyFieldClassMemberDeclarator(PropertyFieldClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsStatic)
                writer.Write("static ");
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            if (n.Value == null)
                writer.Write(" ");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            if (n.Value != null)
            {
                writer.Write(" = ");
                WriteExpression(n.Value, writer);
            }
            writer.Write("\n");
        }

        public virtual void WritePropertyBlockClassMemberDeclarator(PropertyBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsStatic)
                writer.Write("static ");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("get");
            WriteClassMethodBody(n.Getter, writer);
            if (n.Setter != null)
            {
                writer.Write("set");
                WriteClassMethodBody(n.Setter, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteVirtualPropertyClassMemberDeclarator(VirtualPropertyClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" => ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteVirtualPropertyFieldClassMemberDeclarator(VirtualPropertyFieldClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            if (n.Value == null)
                writer.Write(" ");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            if (n.Value != null)
            {
                writer.Write(" = ");
                WriteExpression(n.Value, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteVirtualPropertyBlockClassMemberDeclarator(VirtualPropertyBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("get");
            WriteClassMethodBody(n.Getter, writer);
            if (n.Setter != null)
            {
                writer.Write("set");
                WriteClassMethodBody(n.Setter, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteAbstractPropertyClassMemberDeclarator(AbstractPropertyClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("abstract ");
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteExplicitPropertyImplClassMemberDeclarator(ExplicitPropertyImplClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" => ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteExplicitPropertyImplFieldClassMemberDeclarator(ExplicitPropertyImplFieldClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            WriteIdentifier(n.Name, writer);
            if (n.IsMutable)
                writer.Write("!");
            if (n.Value == null)
                writer.Write(" ");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            if (n.Value != null)
            {
                writer.Write(" = ");
                WriteExpression(n.Value, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteExplicitPropertyImplBlockClassMemberDeclarator(ExplicitPropertyImplBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            WriteIdentifier(n.Name, writer);
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("get");
            WriteClassMethodBody(n.Getter, writer);
            if (n.Setter != null)
            {
                writer.Write("set");
                WriteClassMethodBody(n.Setter, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteIndexerClassMemberDeclarator(IndexerClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("this[");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" => ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteIndexerBlockClassMemberDeclarator(IndexerBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("this[");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("get");
            WriteClassMethodBody(n.Getter, writer);
            if (n.Setter != null)
            {
                writer.Write("set");
                WriteClassMethodBody(n.Setter, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteVirtualIndexerClassMemberDeclarator(VirtualIndexerClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            writer.Write("this[");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" => ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteVirtualIndexerBlockClassMemberDeclarator(VirtualIndexerBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            writer.Write("this[");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("get");
            WriteClassMethodBody(n.Getter, writer);
            if (n.Setter != null)
            {
                writer.Write("set");
                WriteClassMethodBody(n.Setter, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteAbstractIndexerClassMemberDeclarator(AbstractIndexerClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("abstract ");
            writer.Write("this[");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            if (n.IsMutable)
                writer.Write("!");
            writer.Write(" : ");
            WriteTypeExpression(n.Type, writer);
            writer.Write("\n");
        }

        public virtual void WriteExplicitIndexerImplClassMemberDeclarator(ExplicitIndexerImplClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            writer.Write("this[");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" => ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteExplicitIndexerImplBlockClassMemberDeclarator(ExplicitIndexerImplBlockClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            WriteParameterList(n.Parameters, writer);
            writer.Write("]");
            writer.Write(": ");
            WriteTypeExpression(n.Type, writer);
            writer.Write(" with\n");
            writer.OpenBlock();
            writer.Write("get");
            WriteClassMethodBody(n.Getter, writer);
            if (n.Setter != null)
            {
                writer.Write("set");
                WriteClassMethodBody(n.Setter, writer);
            }
            writer.CloseBlock();
        }

        public virtual void WriteMethodClassMemberDeclarator(MethodClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsStatic && n.Access != ClassMemberAccessibility.Private ||
                !n.IsStatic && n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsAsync)
                writer.Write("async ");
            if (n.IsStatic)
                writer.Write("static ");
            writer.Write("def ");
            WriteIdentifier(n.Name, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            WriteClassMethodBody(n.Body, writer);
        }

        public virtual void WriteVirtualMethodClassMemberDeclarator(VirtualMethodClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            if (n.IsAsync)
                writer.Write("async ");
            WriteClassMemberVirtualModifier(n.Modifier, writer);
            writer.Write(" ");
            WriteIdentifier(n.Name, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            WriteClassMethodBody(n.Body, writer);
        }

        public virtual void WriteAbstractMethodClassMemberDeclarator(AbstractMethodClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("abstract ");
            WriteIdentifier(n.Name, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteExplicitMethodImplClassMemberDeclarator(ExplicitMethodImplClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsAsync)
                writer.Write("async ");
            writer.Write("def ");
            WriteTypeExpression(n.Target, writer);
            writer.Write("::");
            WriteIdentifier(n.Name, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            WriteClassMethodBody(n.Body, writer);
        }

        public virtual void WriteConstructorClassMemberDeclarator(ConstructorClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("def new");
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            WriteClassMethodBody(n.Body, writer);
        }

        public virtual void WriteConstructorWithThisClassMemberDeclarator(ConstructorWithThisClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("def new");
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            writer.Write(" with this");
            WriteArgumentList(n.Arguments, writer);
            WriteClassMethodBody(n.Body, writer);
        }

        public virtual void WriteConstructorWithBaseClassMemberDeclarator(ConstructorWithBaseClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Access != ClassMemberAccessibility.Public)
            {
                WriteClassMemberAccessibility(n.Access, writer);
                writer.Write(" ");
            }
            writer.Write("def new");
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            writer.Write(" with base");
            WriteArgumentList(n.Arguments, writer);
            WriteClassMethodBody(n.Body, writer);
        }

        public virtual void WriteStaticConstructorClassMemberDeclarator(StaticConstructorClassMemberDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("static new()");
            WriteClassMethodBody(n.Body, writer);
        }

        public virtual void WriteEnumDeclarator(EnumDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            WriteIdentifier(n.Name, writer);
            writer.Write(":");
            if (n.IsReversed)
                writer.Write(" reversed");
            writer.Write(" one of");
            writer.Write("\n");
            writer.OpenBlock();
            if (n.Items.Count == 0)
                writer.Write("pass\n");
            else
                foreach (EnumItemDeclarator item in n.Items)
                    WriteEnumItemDeclarator(item, writer);
            writer.CloseBlock();
        }

        public virtual void WriteEnumTypeDeclarator(EnumDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            writer.Write("enum ");
            WriteIdentifier(n.Name, writer);
            writer.Write(":");
            if (n.IsReversed)
                writer.Write(" reversed");
            writer.Write("\n");
            writer.OpenBlock();
            if (n.Items.Count == 0)
                writer.Write("pass\n");
            else
                foreach (EnumItemDeclarator item in n.Items)
                    WriteEnumItemDeclarator(item, writer);
            writer.CloseBlock();
        }

        public virtual void WriteStructDeclarator(StructDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            WriteIdentifier(n.Name, writer);
            writer.Write(" = ");
            if (n.IsValueType)
                writer.Write("struct");
            writer.Write("(");
            for (int i = 0; i < n.Fields.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteStructFieldDeclarator(n.Fields[i], writer);
            }
            writer.Write(")");
            writer.Write("\n");
        }

        public virtual void WriteStructTypeDeclarator(StructDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            writer.Write("type ");
            WriteIdentifier(n.Name, writer);
            writer.Write(" = ");
            if (n.IsValueType)
                writer.Write("struct");
            writer.Write("(");
            for (int i = 0; i < n.Fields.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteStructFieldDeclarator(n.Fields[i], writer);
            }
            writer.Write(")");
            writer.Write("\n");
        }

        public virtual void WriteUnionDeclarator(UnionDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            WriteIdentifier(n.Name, writer);
            writer.Write(":");
            writer.Write("\n");
            writer.OpenBlock();
            WriteUnionCaseDeclaratorSuite(n.Cases, writer);
            writer.CloseBlock();
        }

        public virtual void WriteUnionTypeDeclarator(UnionDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            writer.Write("union ");
            WriteIdentifier(n.Name, writer);
            writer.Write(":");
            writer.Write("\n");
            writer.OpenBlock();
            WriteUnionCaseDeclaratorSuite(n.Cases, writer);
            writer.CloseBlock();
        }

        public virtual void WriteVisitorDeclarator(VisitorDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            WriteIdentifier(n.Name, writer);
            writer.Write(".");
            WriteIdentifier(n.MethodNamePrefix, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteVisitorTypeDeclarator(VisitorDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            writer.Write("type ");
            WriteIdentifier(n.Name, writer);
            writer.Write(".");
            WriteIdentifier(n.MethodNamePrefix, writer);
            writer.Write("(");
            WriteParameterList(n.Parameters, writer);
            writer.Write(")");
            if (n.ResultType != null)
            {
                writer.Write(" -> ");
                WriteTypeExpression(n.ResultType, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteInterfaceDeclarator(InterfaceDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            writer.Write("interface ");
            WriteIdentifier(n.Name, writer);
            if (n.Bases.Count > 0)
            {
                writer.Write("(");
                for (int i = 0; i < n.Bases.Count; i++)
                {
                    if (i > 0)
                        writer.Write(", ");
                    WriteTypeExpression(n.Bases[i], writer);
                }
                writer.Write(")");
            }
            writer.Write(":");
            writer.Write("\n");
            writer.OpenBlock();
            if (n.Members.Count == 0)
                writer.Write("pass\n");
            else
                foreach (InterfaceMemberDeclarator item in n.Members)
                    WriteInterfaceMemberDeclarator(item, writer);
            writer.CloseBlock();
        }

        protected virtual bool HaveComplexLogic(ClassMethodBody body1, ClassMethodBody body2)
        {
            return body1 != null && body1.IsBlock || body2 != null && body2.IsBlock;
        }

        protected virtual bool ClassMemberHasComplexBody(ClassMemberDeclarator n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            switch (n.Tag)
            {
                case ClassMemberDeclaratorCategory.EventBlock:
                    return HaveComplexLogic(n.AsEventBlock.Adder, n.AsEventBlock.Remover);
                case ClassMemberDeclaratorCategory.VirtualEventBlock:
                    return HaveComplexLogic(n.AsVirtualEventBlock.Adder, n.AsVirtualEventBlock.Remover);
                case ClassMemberDeclaratorCategory.ExplicitEventImplBlock:
                    return HaveComplexLogic(n.AsExplicitEventImplBlock.Adder, n.AsExplicitEventImplBlock.Remover);
                case ClassMemberDeclaratorCategory.PropertyBlock:
                    return HaveComplexLogic(n.AsPropertyBlock.Getter, n.AsPropertyBlock.Setter);
                case ClassMemberDeclaratorCategory.VirtualPropertyBlock:
                    return HaveComplexLogic(n.AsVirtualPropertyBlock.Getter, n.AsVirtualPropertyBlock.Setter);
                case ClassMemberDeclaratorCategory.ExplicitPropertyImplBlock:
                    return HaveComplexLogic(n.AsExplicitPropertyImplBlock.Getter, n.AsExplicitPropertyImplBlock.Setter);
                case ClassMemberDeclaratorCategory.IndexerBlock:
                    return HaveComplexLogic(n.AsIndexerBlock.Getter, n.AsIndexerBlock.Setter);
                case ClassMemberDeclaratorCategory.VirtualIndexerBlock:
                    return HaveComplexLogic(n.AsVirtualIndexerBlock.Getter, n.AsVirtualIndexerBlock.Setter);
                case ClassMemberDeclaratorCategory.ExplicitIndexerImplBlock:
                    return HaveComplexLogic(n.AsExplicitIndexerImplBlock.Getter, n.AsExplicitIndexerImplBlock.Setter);
                case ClassMemberDeclaratorCategory.Method:
                    return HaveComplexLogic(n.AsMethod.Body, null);
                case ClassMemberDeclaratorCategory.VirtualMethod:
                    return HaveComplexLogic(n.AsVirtualMethod.Body, null);
                case ClassMemberDeclaratorCategory.ExplicitMethodImpl:
                    return HaveComplexLogic(n.AsExplicitMethodImpl.Body, null);
                case ClassMemberDeclaratorCategory.Constructor:
                    return HaveComplexLogic(n.AsConstructor.Body, null);
                case ClassMemberDeclaratorCategory.ConstructorWithThis:
                    return HaveComplexLogic(n.AsConstructorWithThis.Body, null);
                case ClassMemberDeclaratorCategory.ConstructorWithBase:
                    return HaveComplexLogic(n.AsConstructorWithBase.Body, null);
                case ClassMemberDeclaratorCategory.StaticConstructor:
                    return HaveComplexLogic(n.AsStaticConstructor.Body, null);
                default:
                    return false;
            }
        }

        public virtual void WriteClassDeclarator(ClassDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.IsInternal)
                writer.Write("internal ");
            else
                writer.Write("public ");
            if (n.Modifier == ClassVirtualModifier.Struct)
                writer.Write("struct");
            else
            {
                if (n.Modifier != ClassVirtualModifier.Sealed)
                {
                    WriteClassVirtualModifier(n.Modifier, writer);
                    writer.Write(" ");
                }
                writer.Write("class");
            }
            writer.Write(" ");
            WriteIdentifier(n.Name, writer);
            if (n.Bases.Count > 0)
            {
                writer.Write("(");
                for (int i = 0; i < n.Bases.Count; i++)
                {
                    if (i > 0)
                        writer.Write(", ");
                    WriteTypeExpression(n.Bases[i], writer);
                }
                writer.Write(")");
            }
            writer.Write(":");
            writer.Write("\n");
            writer.OpenBlock();
            if (n.Members.Count == 0)
                writer.Write("pass\n");
            else
            {
                for (int i = 0; i < n.Members.Count; i++)
                {
                    ClassMemberDeclarator item = n.Members[i];
                    if (i > 0 && ClassMemberHasComplexBody(item))
                        writer.Write("\n");
                    WriteClassMemberDeclarator(item, writer);
                }
            }
            writer.CloseBlock();
        }

        public virtual void WriteEnumTypeDeclarator(EnumTypeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteEnumDeclarator(n.Declarator, writer);
        }

        public virtual void WriteStructTypeDeclarator(StructTypeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStructDeclarator(n.Declarator, writer);
        }

        public virtual void WriteUnionTypeDeclarator(UnionTypeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteUnionDeclarator(n.Declarator, writer);
        }

        public virtual void WriteVisitorTypeDeclarator(VisitorTypeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteVisitorDeclarator(n.Declarator, writer);
        }

        public virtual void WriteInterfaceTypeDeclarator(InterfaceTypeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteInterfaceDeclarator(n.Declarator, writer);
        }

        public virtual void WriteClassTypeDeclarator(ClassTypeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteClassDeclarator(n.Declarator, writer);
        }

        public virtual void WriteTypeDeclaration(TypeDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Declarators.Count; i++)
            {
                if (i > 0)
                    writer.Write("\n");
                WriteTypeDeclarator(n.Declarators[i], writer);
            }
        }

        public virtual void WriteEmptySyntacticExpression(EmptySyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("()");
        }

        public virtual void WriteQuoteStringSyntacticExpression(QuoteStringSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteQuoteStringLiteral(n.Value, writer);
        }

        public virtual void WriteNameReferenceSyntacticExpression(NameReferenceSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WriteKleeneSyntacticExpression(KleeneSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixSyntacticExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteSyntacticExpression(n.Operand, writer, prec);
            string str = n.Operand.ToString(this);
            if (str.EndsWith("*"))
                writer.Write(" ");
            writer.Write("*");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteOptionalSyntacticExpression(OptionalSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixSyntacticExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteSyntacticExpression(n.Operand, writer, prec);
            writer.Write("?");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WritePositiveSyntacticExpression(PositiveSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixSyntacticExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteSyntacticExpression(n.Operand, writer, prec);
            string str = n.Operand.ToString(this);
            if (str.EndsWith("+"))
                writer.Write(" ");
            writer.Write("+");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteSequenceSyntacticExpression(SequenceSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixSyntacticExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteSyntacticExpression(n.Operand, writer, prec);
            writer.Write(" ");
            writer.Write(n.IsNullable ? "%" : "%+");
            writer.Write(" ");
            WriteQuoteStringLiteral(n.Separator, writer);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteConcatSyntacticExpression(ConcatSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = ConcatSyntacticExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteSyntacticExpression(n.Left, writer, prec);
            writer.Write(" ");
            WriteSyntacticExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteUnionSyntacticExpression(UnionSyntacticExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = SyntacticExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteSyntacticExpression(n.Left, writer, prec);
            writer.Write(" | ");
            WriteSyntacticExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteSyntacticRuleDeclarator(SyntacticRuleDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (!n.Pattern.IsEmpty)
                WriteSyntacticExpression(n.Pattern, writer);
            if (n.Precedence != null)
            {
                if (!n.Pattern.IsEmpty)
                    writer.Write(" ");
                writer.Write("%prec ");
                WriteTokenReference(n.Precedence, writer);
            }
            if (n.Action == null)
                writer.Write("\n");
            else
            {
                if (!n.Pattern.IsEmpty || n.Precedence != null)
                    writer.Write(" ");
                WriteSemanticAction(n.Action, writer);
            }
        }

        public virtual void WriteSyntacticDeclarator(SyntacticDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.Type != null)
            {
                writer.Write(" as ");
                WriteTypeExpression(n.Type, writer);
            }
            writer.Write(":\n");
            writer.OpenBlock();
            if (n.Rules.Count == 0)
                writer.Write("pass\n");
            else
                foreach (SyntacticRuleDeclarator item in n.Rules)
                    WriteSyntacticRuleDeclarator(item, writer);
            writer.CloseBlock();
        }

        public virtual void WriteSyntacticDeclaration(SyntacticDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Declarators.Count; i++)
            {
                if (i > 0)
                    writer.Write("\n");
                WriteSyntacticDeclarator(n.Declarators[i], writer);
            }
        }

        public virtual void WriteCharIntervalDescriptor(CharIntervalDescriptor n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteCharLiteral(n.First, writer);
            if (n.First.Value != n.Last.Value)
            {
                writer.Write("-");
                WriteCharLiteral(n.Last, writer);
            }
        }

        public virtual void WriteCharClassDescriptor(CharClassDescriptor n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(n.IsNegated ? "[^" : "[");
            for (int i = 0; i < n.Intervals.Count; i++)
            {
                if (i > 0)
                    writer.Write(" ");
                CharIntervalDescriptor item = n.Intervals[i];
                WriteCharIntervalDescriptor(item, writer);
            }
            writer.Write("]");
        }

        public virtual void WriteEmptyLexicalExpression(EmptyLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("()");
        }

        public virtual void WriteStringLexicalExpression(StringLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStringLiteral(n.Value, writer);
        }

        public virtual void WriteQuoteStringLexicalExpression(QuoteStringLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteQuoteStringLiteral(n.Value, writer);
        }

        public virtual void WriteCharClassLexicalExpression(CharClassLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteCharClassDescriptor(n.Value, writer);
        }

        public virtual void WriteNameReferenceLexicalExpression(NameReferenceLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WriteKleeneLexicalExpression(KleeneLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixLexicalExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteLexicalExpression(n.Operand, writer, prec);
            string str = n.Operand.ToString(this);
            if (str.EndsWith("*"))
                writer.Write(" ");
            writer.Write("*");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteOptionalLexicalExpression(OptionalLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixLexicalExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteLexicalExpression(n.Operand, writer, prec);
            writer.Write("?");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WritePositiveLexicalExpression(PositiveLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = PostfixLexicalExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteLexicalExpression(n.Operand, writer, prec);
            string str = n.Operand.ToString(this);
            if (str.EndsWith("+"))
                writer.Write(" ");
            writer.Write("+");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteRepeatLexicalExpression(RepeatLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.MinCount == null && n.MaxCount == null)
            {
                AssertionErrorException e = new AssertionErrorException(SR.MinCountMaxCountBothOmitted);
                e.AddLocation(n.Context);
                throw e;
            }
            if (n.MinCount.Value < 0)
            {
                AssertionErrorException e = new AssertionErrorException(SR.MinCountMustBeNonNegative);
                e.AddLocation(n.Context);
                e.AddLocation(n.MinCount.Context);
                throw e;
            }
            if (n.MaxCount.Value <= 0)
            {
                AssertionErrorException e = new AssertionErrorException(SR.MaxCountMustBePositive);
                e.AddLocation(n.Context);
                e.AddLocation(n.MaxCount.Context);
                throw e;
            }
            if (n.MinCount.Value > n.MaxCount.Value)
            {
                AssertionErrorException e = new AssertionErrorException(SR.MinCountMaxCountNotRange);
                e.AddLocation(n.Context);
                e.AddLocation(n.MinCount.Context);
                e.AddLocation(n.MaxCount.Context);
                throw e;
            }
            const int prec = PostfixLexicalExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteLexicalExpression(n.Operand, writer, prec);
            writer.Write("{");
            if (n.MinCount == null)
            {
                writer.Write(",");
                WriteIntegerLiteral(n.MaxCount, writer);
            }
            else if (n.MaxCount == null)
            {
                WriteIntegerLiteral(n.MinCount, writer);
                writer.Write(",");
            }
            else if (n.MinCount.Value == n.MaxCount.Value)
                WriteIntegerLiteral(n.MinCount, writer);
            else
            {
                WriteIntegerLiteral(n.MinCount, writer);
                writer.Write(",");
                WriteIntegerLiteral(n.MaxCount, writer);
            }
            writer.Write("}");
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteConcatLexicalExpression(ConcatLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = ConcatLexicalExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteLexicalExpression(n.Left, writer, prec);
            writer.Write(" ");
            WriteLexicalExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteUnionLexicalExpression(UnionLexicalExpression n, IndentedWriter writer, int d)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            const int prec = LexicalExpressionOpPrecedence;
            if (d > prec)
                writer.Write("(");
            WriteLexicalExpression(n.Left, writer, prec);
            writer.Write(" | ");
            WriteLexicalExpression(n.Right, writer, prec + 1);
            if (d > prec)
                writer.Write(")");
        }

        public virtual void WriteLexicalAliasDeclarator(LexicalAliasDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            writer.Write(" = ");
            WriteLexicalExpression(n.Pattern, writer);
            writer.Write("\n");
        }

        public virtual void WriteLexicalStartReferenceSet(LexicalStartReferenceSet n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Names.Count == 1 && !n.IncludesNonExclusive && !n.IncludesAll)
                WriteIdentifier(n.Names[0], writer);
            else
            {
                writer.Write("<");
                if (n.IncludesAll)
                    writer.Write("**");
                else
                {
                    for (int i = 0; i < n.Names.Count; i++)
                    {
                        if (i > 0)
                            writer.Write(", ");
                        WriteIdentifier(n.Names[i], writer);
                    }
                    if (n.IncludesNonExclusive)
                    {
                        if (n.Names.Count > 0)
                            writer.Write(", ");
                        writer.Write("*");
                    }
                }
                writer.Write(">");
            }
        }

        public virtual void WriteLexicalRuleDeclarator(LexicalRuleDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.AtLineBegin)
                writer.Write("^ ");
            WriteLexicalExpression(n.Pattern, writer);
            if (n.AtLineEnd)
                writer.Write(" $");
            if (n.Action == null)
                writer.Write("\n");
            else
            {
                writer.Write(" ");
                WriteSemanticAction(n.Action, writer);
            }
        }

        public virtual void WriteLexicalStartDeclarator(LexicalStartDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteLexicalStartReferenceSet(n.Starts, writer);
            writer.Write(":\n");
            writer.OpenBlock();
            foreach (LexicalRuleDeclarator rule in n.Rules)
                WriteLexicalRuleDeclarator(rule, writer);
            if (n.DefaultAction != null)
            {
                writer.Write("default ");
                WriteSemanticAction(n.DefaultAction, writer);
            }
            if (n.Rules.Count == 0 && n.DefaultAction == null)
                writer.Write("pass\n");
            writer.CloseBlock();
        }

        public virtual void WriteAliasLexicalDeclarator(AliasLexicalDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteLexicalAliasDeclarator(n.Declarator, writer);
        }

        public virtual void WriteStartLexicalDeclarator(StartLexicalDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteLexicalStartDeclarator(n.Declarator, writer);
        }

        public virtual void WriteLexicalDeclaration(LexicalDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Declarators.Count; i++)
            {
                if (i > 0)
                    writer.Write("\n");
                WriteLexicalDeclarator(n.Declarators[i], writer);
            }
        }

        public virtual void WriteTokenDeclarator(TokenDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Name == null)
            {
                if (n.Value == null)
                {
                    AssertionErrorException e = new AssertionErrorException(SR.LiteralTokenMustHaveValueSet);
                    e.AddLocation(n.Context);
                    throw e;
                }
                if (n.Text != null)
                {
                    AssertionErrorException e = new AssertionErrorException(SR.LiteralTokenMustNotHaveTextSet);
                    e.AddLocation(n.Context);
                    throw e;
                }
                WriteQuoteStringLiteral(n.Value, writer);
            }
            else
            {
                if (n.Value != null && n.Text != null)
                {
                    AssertionErrorException e = new AssertionErrorException(SR.NamedTokenMustNotHaveValueAndTextBothSet);
                    e.AddLocation(n.Context);
                    throw e;
                }
                WriteIdentifier(n.Name, writer);
                if (n.Value != null || n.Text != null)
                {
                    writer.Write(" (");
                    if (n.Value != null)
                        WriteQuoteStringLiteral(n.Value, writer);
                    else
                        WriteStringLiteral(n.Text, writer);
                    writer.Write(")");
                }
            }
        }

        public virtual void WriteTokenDeclarationKind(TokenDeclarationKind n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n)
            {
                case TokenDeclarationKind.Token: writer.Write("%token"); break;
                case TokenDeclarationKind.EndMarker: writer.Write("%endmarker"); break;
                case TokenDeclarationKind.LayoutMarker: writer.Write("%layout"); break;
                case TokenDeclarationKind.HiddenToken: writer.Write("%hidden"); break;
                case TokenDeclarationKind.Keyword: writer.Write("%keyword"); break;
                case TokenDeclarationKind.ReservedWord: writer.Write("%reserved"); break;
                case TokenDeclarationKind.ContextualWord: writer.Write("%contextual"); break;
                default:
                    throw new ArgumentException(SR.InvalidTokenDeclarationKind, nameof(n));
            }
        }

        public virtual void WriteTokenDeclaration(TokenDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTokenDeclarationKind(n.Kind, writer);
            writer.Write(" ");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteTokenDeclarator(n.Items[i], writer);
            }
            if (n.AssignedType != null)
            {
                writer.Write(" : ");
                WriteTypeExpression(n.AssignedType, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteNamedTokenReference(NamedTokenReference n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WriteLiteralTokenReference(LiteralTokenReference n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteQuoteStringLiteral(n.Value, writer);
        }

        public virtual void WriteOperatorDeclarationKind(OperatorDeclarationKind n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n)
            {
                case OperatorDeclarationKind.Left: writer.Write("%left"); break;
                case OperatorDeclarationKind.Right: writer.Write("%right"); break;
                case OperatorDeclarationKind.Nonassociative: writer.Write("%nonassoc"); break;
                case OperatorDeclarationKind.Shift: writer.Write("%shift"); break;
                case OperatorDeclarationKind.Reduce: writer.Write("%reduce"); break;
                default:
                    throw new ArgumentException(SR.InvalidOperatorDeclarationKind, nameof(n));
            }
        }

        public virtual void WriteOperatorDeclaration(OperatorDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteOperatorDeclarationKind(n.Kind, writer);
            writer.Write(" ");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteTokenReference(n.Items[i], writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteStartDeclaration(StartDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(n.IsExclusive ? "%xstart" : "%start");
            writer.Write(" ");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteIdentifier(n.Items[i], writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteGoalDeclarator(GoalDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.EndMarkers.Count > 0)
            {
                writer.Write(" % ");
                if (n.EndMarkers.Count == 1)
                    WriteTokenReference(n.EndMarkers[0], writer);
                else
                {
                    writer.Write("{");
                    for (int i = 0; i < n.EndMarkers.Count; i++)
                    {
                        if (i > 0)
                            writer.Write(", ");
                        WriteTokenReference(n.EndMarkers[i], writer);
                    }
                    writer.Write("}");
                }
            }
        }

        public virtual void WriteGoalDeclaration(GoalDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("%goal");
            writer.Write(" ");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteGoalDeclarator(n.Items[i], writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteLexicalPrecedenceOperator(LexicalPrecedenceOperator n, IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            switch (n)
            {
                case LexicalPrecedenceOperator.LessTilde: writer.Write("<~"); break;
                case LexicalPrecedenceOperator.LessMinus: writer.Write("<-"); break;
                case LexicalPrecedenceOperator.MinusTilde: writer.Write("-~"); break;
                case LexicalPrecedenceOperator.LessLess: writer.Write("<<"); break;
                case LexicalPrecedenceOperator.LessS: writer.Write("<s"); break;
                case LexicalPrecedenceOperator.MinusLess: writer.Write("-<"); break;
                case LexicalPrecedenceOperator.MinusS: writer.Write("-s"); break;
                default:
                    throw new ArgumentException(SR.InvalidLexicalPrecedenceOperator, nameof(n));
            }
        }

        public virtual void WriteLexicalPrecedenceDeclarator(LexicalPrecedenceDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTokenReference(n.Left, writer);
            writer.Write(" ");
            WriteLexicalPrecedenceOperator(n.Op, writer);
            writer.Write(" ");
            WriteTokenReference(n.Right, writer);
        }

        public virtual void WriteLexicalPrecedenceDeclaration(LexicalPrecedenceDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("%lexprec");
            writer.Write(" ");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteLexicalPrecedenceDeclarator(n.Items[i], writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteExceptionDescriptor(ExceptionDescriptor n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
            if (n.BaseName != null)
            {
                writer.Write(" : ");
                WriteIdentifier(n.BaseName, writer);
            }
        }

        public virtual void WriteExceptionDeclaration(ExceptionDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("%exception");
            writer.Write(" ");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteIdentifier(n.Items[i], writer);
            }
            if (n.BaseName != null)
            {
                writer.Write(" : ");
                WriteIdentifier(n.BaseName, writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteDefineDeclaration(DefineDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("%define");
            writer.Write(" ");
            for (int i = 0; i < n.Name.Count; i++)
            {
                if (i > 0)
                    writer.Write(".");
                WriteIdentifier(n.Name[i], writer);
            }
            writer.Write(" ");
            WriteExpression(n.Value, writer);
            writer.Write("\n");
        }

        public virtual void WriteNamedIncludeDeclarator(NamedIncludeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Name.Count; i++)
            {
                if (i > 0)
                    writer.Write(".");
                WriteIdentifier(n.Name[i], writer);
            }
        }

        public virtual void WriteLiteralIncludeDeclarator(LiteralIncludeDeclarator n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStringLiteral(n.Value, writer);
        }

        public virtual void WriteIncludeDeclaration(IncludeDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("%include");
            writer.Write(" ");
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteIncludeDeclarator(n.Items[i], writer);
            }
            writer.Write("\n");
        }

        public virtual void WriteTokenDirective(TokenDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTokenDeclaration(n.Declaration, writer);
        }

        public virtual void WriteOperatorDirective(OperatorDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteOperatorDeclaration(n.Declaration, writer);
        }

        public virtual void WriteStartDirective(StartDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteStartDeclaration(n.Declaration, writer);
        }

        public virtual void WriteGoalDirective(GoalDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteGoalDeclaration(n.Declaration, writer);
        }

        public virtual void WriteLexicalPrecedenceDirective(LexicalPrecedenceDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteLexicalPrecedenceDeclaration(n.Declaration, writer);
        }

        public virtual void WriteExceptionDirective(ExceptionDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteExceptionDeclaration(n.Declaration, writer);
        }

        public virtual void WriteDefineDirective(DefineDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDefineDeclaration(n.Declaration, writer);
        }

        public virtual void WriteIncludeDirective(IncludeDirective n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIncludeDeclaration(n.Declaration, writer);
        }

        public virtual void WriteDirectiveDeclaration(DirectiveDeclaration n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Items.Count; i++)
                WriteDirective(n.Items[i], writer);
        }
    }
}
